package model

import (
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"gorm.io/gorm"
	"time"
)

const (
	GLUCOSE_UNIT_MMOL_L = 1
	GLUCOSE_UNIT_MOL_L  = 2
)

type GlucoseUnit struct {
	int8
}

func (g GlucoseUnit) GetValue() int8 {
	return g.int8
}

func (g *GlucoseUnit) UnmarshalJSON(data []byte) error {
	unit := string(data)
	if unit == `"mmol/L"` {
		g.int8 = GLUCOSE_UNIT_MMOL_L
	} else { // default mol/L
		g.int8 = GLUCOSE_UNIT_MOL_L
	}

	return nil
}

func (g GlucoseUnit) MarshalJSON() ([]byte, error) {
	var str string
	if g.int8 == GLUCOSE_UNIT_MMOL_L {
		str = "mmol/L"
	} else {
		str = "mol/L"
	}
	return json.Marshal(str)
}

// 写入数据库之前，对数据做类型转换
func (g GlucoseUnit) Value() (driver.Value, error) {
	return fmt.Sprintf("%d", g.int8), nil
}

// 将数据库中取出的数据，赋值给目标类型
func (g *GlucoseUnit) Scan(v any) error {
	bytes, ok := v.(int64)
	if !ok {
		return errors.New("fail to scan")
	}
	g.int8 = int8(bytes)
	return nil
}

type UserDetailModel struct {
	UserId                             uint    `json:"user_id" gorm:"primary_key"`
	PatientNumber                      string  `json:"patient_number"`
	Gender                             int8    `json:"gender"`
	Age                                int8    `json:"age"`
	Height                             float32 `json:"height"`
	Weight                             float32 `json:"weight"`
	IllnessDuration                    float32 `json:"illness_duration"`
	BMI                                float32 `json:"bmi" gorm:"-"`
	SmokingHistory                     float32 `json:"smoking_history"`
	AlcoholDrinkingHistory             string  `json:"alcohol_drinking_history"`
	TypeOfDiabetes                     string  `json:"type_of_diabetes"`
	DurationOfDiabetes                 float32 `json:"duration_of_diabetes"`
	AcuteDiabeticComplications         string  `json:"acute_diabetic_complications"`
	DiabeticMacrovascularComplications string  `json:"diabetic_macrovascular_complications"`
	DiabeticMicrovascularComplications string  `json:"diabetic_microvascular_complications"`
	Comorbidities                      string  `json:"comorbidities"`
	HypoglycemicAgents                 string  `json:"hypoglycemic_agents"`
	OtherAgents                        string  `json:"other_agents"`
	FastingPlasmaGlucose               float32 `json:"fasting_plasma_glucose"`
	TwoHourPostprandialPlasmaGlucose   float32 `json:"two_hour_postprandial_plasma_glucose"`
	FastingCPeptide                    float32 `json:"fasting_c_peptide" gorm:"column:fasting_c_peptide"`
	TwoHourPostprandialCPeptide        float32 `json:"two_hour_postprandial_c_peptide" gorm:"column:two_hour_postprandial_c_peptide"`
	FastingInsulin                     float32 `json:"fasting_insulin"`
	TwoHourPostprandialInsulin         float32 `json:"two_hour_postprandial_insulin"`
	Hba1c                              float32 `json:"hba1c" gorm:"column:hba1c"`
	GlycatedAlbumin                    float32 `json:"glycated_albumin"`
	TotalCholesterol                   float32 `json:"total_cholesterol"`
	Triglyceride                       float32 `json:"triglyceride"`
	HighDensityLipoproteinCholesterol  float32 `json:"high_density_lipoprotein_cholesterol"`
	LowDensityLipoproteinCholesterol   float32 `json:"low_density_lipoprotein_cholesterol"`
	Creatinine                         float32 `json:"creatinine"`
	EstimatedGlomerularFiltrationRate  int16   `json:"estimated_glomerular_filtration_rate"`
	UricAcid                           float32 `json:"uric_acid"`
	BloodUreaNitrogen                  float32 `json:"blood_urea_nitrogen"`
	Hypoglycemia                       int8    `json:"hypoglycemia"`
}

type UserDetail struct {
	UserDetailModel
	Birthday    time.Time   `json:"birthday"`
	GlucoseUnit GlucoseUnit `json:"glucose_unit"`
}

func (u *UserDetail) Create(db *gorm.DB) error {
	return db.Create(u).Error
}

func (u *UserDetail) Get(db *gorm.DB) error {
	return db.First(u).Error
}

func (u *UserDetail) Save(db *gorm.DB) error {
	return db.Save(u).Error
}

func (u *UserDetail) Update(db *gorm.DB) error {
	return db.Model(u).Where(Eq("user_id", u.UserId)).Updates(u).Error
}

func (u *UserDetail) GetByNumber(db *gorm.DB) error {
	return db.First(u, "patient_number = ?", u.PatientNumber).Error
}

func (u *UserDetail) GetByUserId(db *gorm.DB) error {
	return db.Where(Eq("user_id", u.UserId)).First(u).Error
}
